﻿using Autofac;
using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using Autofac.Extras.DynamicProxy;

namespace Quickuse.Ioc
{

    /// <summary>
    /// 依赖配置
    /// </summary>
    public class DependencyConfig : IDependencyConfig
    {
        private static readonly List<RegisterType> registerTypes = new List<RegisterType>();     //注册类型集合
        private static Type[] _interceptorServiceTypes = new Type[] { };           //注册拦截器类型

        /// <summary>
        /// 注册依赖项
        /// </summary>
        /// <param name="builder">builder</param>
        public static void RegisterDependency(ContainerBuilder builder)
        {
            var enumerable = typeof(DependencyConfig).Assembly.GetTypes()
                    .Where(p => typeof(IDependency).IsAssignableFrom(p) && p.IsClass);

            var currents = enumerable as Type[] ?? enumerable.ToArray();

            if (currents.Any())
            {
                foreach (var current in currents)
                {
                    var type = current.GetInterfaces().FirstOrDefault(p =>
                            typeof(IDependency).IsAssignableFrom(p)
                            && !string.Equals(p.Name, "IDependency", StringComparison.CurrentCultureIgnoreCase)
                            && p.Name.IndexOf("IBase", StringComparison.CurrentCultureIgnoreCase) < 0);

                    if (type != null)
                    {
                        builder.RegisterType(current).As(type);
                    }
                }
            }
        }

        /// <summary>
        /// 注册依赖项
        /// </summary>
        /// <param name="assembly">assembly</param>
        /// <param name="builder">builder</param>
        /// <param name="interceptorTypes">interceptorTypes</param>
        public static void RegisterDependency(Assembly assembly, ContainerBuilder builder, params Type[] interceptorTypes)
        {
            try
            {
                builder.RegisterTypes(interceptorTypes);
                _interceptorServiceTypes = interceptorTypes;

                var enumerable = assembly.GetTypes().Where(p => typeof(IDependency).IsAssignableFrom(p) && p.IsClass);

                var assemblyTypeArray = (enumerable as Type[]) ?? enumerable.ToArray();
                if (assemblyTypeArray.Any())
                {
                    foreach (var assemblyType in assemblyTypeArray)
                    {
                        //获取类型继承IDependency的接口过滤IDependency并且接口名不能含有IBase字符串
                        var iassemblyType = assemblyType.GetInterfaces().FirstOrDefault(p =>
                            typeof(IDependency).IsAssignableFrom(p)
                            && !string.Equals(p.Name, "IDependency", StringComparison.CurrentCultureIgnoreCase)
                            && p.Name.IndexOf("IBase", StringComparison.CurrentCultureIgnoreCase) < 0);

                        if (iassemblyType != null)
                        {
                            var named = assemblyType.GetCustomAttribute<NamedAttribute>()?.Named;

                            var singleInstance = iassemblyType.GetCustomAttribute<SingleInstanceAttribute>();
                            var instancePerOwned = iassemblyType.GetCustomAttribute<InstancePerRequestAttribute>();
                            var propertiesAutowired = iassemblyType.GetCustomAttribute<PropertiesAutowiredAttribute>();

                            if (singleInstance != null)
                            {
                                RegisterSingleInstance(builder, assemblyType, iassemblyType, propertiesAutowired, named);
                            }
                            else if (instancePerOwned != null)
                            {
                                RegisterInstancePerRequest(builder, assemblyType, iassemblyType, propertiesAutowired, named);
                            }
                            else
                            {
                                RegisterInstancePerDependency(builder, assemblyType, iassemblyType, propertiesAutowired, named);
                            }
                        }
                    }
                }

                RegisterServices(builder);

            }
            catch (Exception ex)
            {
                IocGlobal.Log.Error($"[[DependencyConfig.RegisterDependency=>{ex.Message}{ex.StackTrace}]]");
            }
        }

        /// <summary>
        /// 注册服务集合
        /// </summary>
        /// <param name="builder"></param>
        internal static void RegisterServices(ContainerBuilder builder)
        {
            if (registerTypes.Count > 0)
            {
                foreach (var registerType in registerTypes)
                {
                    if (registerType.RegisterMode == 1)
                    {
                        //实例
                        switch (registerType.RegisterEnum)
                        {
                            case RegisterTypeEnum.Single://单例
                                builder.RegisterInstance(registerType.Instance).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .SingleInstance();
                                break;
                            case RegisterTypeEnum.PerLifetimeScope://作用域
                                builder.RegisterInstance(registerType.Instance).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .InstancePerLifetimeScope();
                                break;
                            case RegisterTypeEnum.PerDependency://瞬时
                                builder.RegisterInstance(registerType.Instance).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .InstancePerDependency();
                                break;
                        }
                    }
                    else
                    {
                        //类型
                        switch (registerType.RegisterEnum)
                        {
                            case RegisterTypeEnum.Single://单例
                                builder.RegisterType(registerType.AssemblyType).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .SingleInstance();
                                break;
                            case RegisterTypeEnum.PerLifetimeScope://作用域
                                builder.RegisterInstance(registerType.AssemblyType).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .InstancePerLifetimeScope();
                                break;
                            case RegisterTypeEnum.PerDependency://瞬时
                                builder.RegisterInstance(registerType.AssemblyType).As(registerType.IAssemblyType)
                                    .EnableInterfaceInterceptors().InterceptedBy(_interceptorServiceTypes)
                                    .InstancePerDependency();
                                break;
                        }
                    }
                }

                registerTypes.Clear();
            }
        }

        ///// <summary>
        ///// 注册拦截器服务
        ///// </summary>
        ///// <param name="interceptorTypes"></param>
        ////internal static void RegisterInterceptorService(params Type[] interceptorTypes)
        ////{
        ////    foreach (var type in interceptorTypes)
        ////    {
        ////        interceptorServiceTypes.Add(type);
        ////    }
        ////}


        #region 注册单一实例
        /// <summary>
        /// 注册单一实例
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assemblyType">类型</param>
        /// <param name="iassemblyType">类型接口</param>
        /// <param name="propertiesAutowired">属性</param>
        /// <param name="named">别名</param>
        private static void RegisterSingleInstance(ContainerBuilder builder, Type assemblyType, Type iassemblyType, PropertiesAutowiredAttribute propertiesAutowired, string named)
        {
            if (string.IsNullOrEmpty(named))
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .SingleInstance();
                }
                else
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .SingleInstance().PropertiesAutowired();
                }
            }
            else
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType).Named(named, iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .SingleInstance();
                }
                else
                {
                    builder.RegisterType(assemblyType).Named(named, iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .SingleInstance().PropertiesAutowired();
                }
            }
        }
        #endregion

        #region 注册 每个请求一个实例
        /// <summary>
        /// 注册 每个请求一个实例
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assemblyType">类型</param>
        /// <param name="iassemblyType">类型接口</param>
        /// <param name="propertiesAutowired">属性</param>
        /// <param name="named">别名</param>
        private static void RegisterInstancePerRequest(ContainerBuilder builder, Type assemblyType, Type iassemblyType, PropertiesAutowiredAttribute propertiesAutowired, string named)
        {
            if (string.IsNullOrEmpty(named))
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .InstancePerLifetimeScope();

                }
                else
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .InstancePerLifetimeScope().PropertiesAutowired();
                }
            }
            else
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType).Named(named, iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .InstancePerLifetimeScope();
                }
                else
                {
                    builder.RegisterType(assemblyType).Named(named, iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .InstancePerLifetimeScope().PropertiesAutowired();
                }
            }
        }
        #endregion

        #region 注册每次请求都会返回一个唯一的实例
        /// <summary>
        /// 注册每次请求都会返回一个唯一的实例
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assemblyType">类型</param>
        /// <param name="iassemblyType">类型接口</param>
        /// <param name="propertiesAutowired">属性</param>
        /// <param name="named">别名</param>
        private static void RegisterInstancePerDependency(ContainerBuilder builder, Type assemblyType, Type iassemblyType, PropertiesAutowiredAttribute propertiesAutowired, string named)
        {
            //默认使用都是新的实例
            if (string.IsNullOrEmpty(named))
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes);
                }
                else
                {
                    builder.RegisterType(assemblyType).As(iassemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .PropertiesAutowired();
                }
            }
            else
            {
                if (propertiesAutowired == null)
                {
                    builder.RegisterType(assemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .Named(named, iassemblyType);
                }
                else
                {
                    builder.RegisterType(assemblyType)
                        .EnableClassInterceptors().InterceptedBy(_interceptorServiceTypes)
                        .Named(named, iassemblyType).PropertiesAutowired();
                }
            }
        }
        #endregion

        #region 注册服务
        /// <summary>
        /// 注册单例服务
        /// </summary>
        /// <param name="assemblyType">类型</param>
        /// <param name="instance">实例</param>
        internal static void RegisterSingleService(Type assemblyType, object instance)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.Single,
                RegisterMode = 1,
                IAssemblyType = assemblyType,
                Instance = instance
            });
        }

        /// <summary>
        /// 注册单例服务
        /// </summary>
        /// <param name="assemblyType">类型</param>
        /// <param name="iassemblyType">类型接口</param>
        internal static void RegisterSingleService(Type assemblyType, Type iassemblyType)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.Single,
                RegisterMode = 0,
                IAssemblyType = iassemblyType,
                AssemblyType = assemblyType
            });
        }

        /// <summary>
        /// 注册作用域服务
        /// </summary>
        /// <param name="assemblyType"></param>
        /// <param name="instance"></param>
        internal static void RegisterScopedService(Type assemblyType, object instance)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.PerLifetimeScope,
                RegisterMode = 1,
                IAssemblyType = assemblyType,
                Instance = instance
            });
        }

        /// <summary>
        /// 注册作用域服务
        /// </summary>
        /// <param name="assemblyType"></param>
        /// <param name="iassemblyType"></param>
        internal static void RegisterScopedService(Type assemblyType, Type iassemblyType)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.PerLifetimeScope,
                RegisterMode = 0,
                IAssemblyType = iassemblyType,
                AssemblyType = assemblyType
            });
        }

        /// <summary>
        /// 注册瞬时服务
        /// </summary>
        /// <param name="assemblyType"></param>
        /// <param name="instance"></param>
        internal static void RegisterPerDependencyService(Type assemblyType, object instance)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.PerDependency,
                RegisterMode = 1,
                IAssemblyType = assemblyType,
                Instance = instance
            });
        }

        /// <summary>
        /// 注册瞬时服务
        /// </summary>
        /// <param name="assemblyType"></param>
        /// <param name="iassemblyType"></param>
        internal static void RegisterPerDependencyService(Type assemblyType, Type iassemblyType)
        {
            registerTypes.Add(new RegisterType()
            {
                RegisterEnum = RegisterTypeEnum.PerDependency,
                RegisterMode = 0,
                IAssemblyType = iassemblyType,
                AssemblyType = assemblyType
            });
        }
        #endregion
    }
}
